home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1865 / 1865.xpi / chrome / adblockplus.jar / content / elemhide.js next >
Text File  |  2010-01-07  |  8KB  |  339 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Adblock Plus.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * Wladimir Palant.
  18.  * Portions created by the Initial Developer are Copyright (C) 2006-2009
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *
  23.  * ***** END LICENSE BLOCK ***** */
  24.  
  25. /**
  26.  * @fileOverview Element hiding implementation.
  27.  * This file is included from AdblockPlus.js.
  28.  */
  29.  
  30. var styleService = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); 
  31.  
  32. /**
  33.  * Element hiding component
  34.  * @class
  35.  */
  36. var elemhide =
  37. {
  38.     /**
  39.      * Class ID for the protocol handler.
  40.      */
  41.     protoCID: Components.ID("{e3823970-1546-11de-8c30-0800200c9a66}"),
  42.  
  43.     /**
  44.      * List of known filters
  45.      * @type Array of ElemHideFilter
  46.      */
  47.     filters: [],
  48.  
  49.     /**
  50.      * Lookup table, has keys for all filters already added
  51.      * @type Object
  52.      */
  53.     knownFilters: {__proto__: null},
  54.  
  55.     /**
  56.      * Lookup table for filters by their associated key
  57.      * @type Object
  58.      */
  59.     keys: {__proto__: null},
  60.  
  61.     /**
  62.      * Currently applied stylesheet URL
  63.      * @type nsIURI
  64.      */
  65.     url: null,
  66.  
  67.     /**
  68.      * Indicates whether filters have been added or removed since the last apply() call.
  69.      * @type Boolean
  70.      */
  71.     isDirty: false,
  72.  
  73.     /**
  74.      * Initialization function, should be called after policy initialization.
  75.      */
  76.     init: function()
  77.     {
  78.         try {
  79.             let compMgr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
  80.             compMgr.registerFactory(this.protoCID, "Element hiding hit registration protocol handler", "@mozilla.org/network/protocol;1?name=" + this.scheme, this);
  81.             policy.whitelistSchemes[this.scheme] = true;
  82.         } catch (e) {}
  83.     },
  84.  
  85.     /**
  86.      * Removes all known filters
  87.      */
  88.     clear: function()
  89.     {
  90.         this.filters = [];
  91.         this.knownFilters= {__proto__: null};
  92.         this.keys = {__proto__: null};
  93.         this.isDirty = false;
  94.         this.unapply();
  95.     },
  96.  
  97.     /**
  98.      * Add a new element hiding filter
  99.      * @param {ElemHideFilter} filter
  100.      */
  101.     add: function(filter)
  102.     {
  103.         if (filter.text in this.knownFilters)
  104.             return;
  105.  
  106.         this.filters.push(filter);
  107.  
  108.         do {
  109.             filter.key = Math.random().toFixed(15).substr(5);
  110.         } while (filter.key in this.keys);
  111.  
  112.         this.keys[filter.key] = filter;
  113.         this.knownFilters[filter.text] = true;
  114.         this.isDirty = true;
  115.     },
  116.  
  117.     /**
  118.      * Removes an element hiding filter
  119.      * @param {ElemHideFilter} filter
  120.      */
  121.     remove: function(filter)
  122.     {
  123.         if (!(filter.text in this.knownFilters))
  124.             return;
  125.  
  126.         let i = this.filters.indexOf(filter);
  127.         if (i >= 0)
  128.             this.filters.splice(i, 1);
  129.  
  130.         delete this.keys[filter.key];
  131.         delete this.knownFilters[filter.text];
  132.         this.isDirty = true;
  133.     },
  134.  
  135.     /**
  136.      * Generates stylesheet URL and applies it globally
  137.      */
  138.     apply: function()
  139.     {
  140.         // Return immediately if nothing to do
  141.         if (!this.url && (!prefs.enabled || !this.filters.length))
  142.             return;
  143.  
  144.  
  145.         this.unapply();
  146.  
  147.  
  148.         this.isDirty = false;
  149.  
  150.         if (!prefs.enabled)
  151.         {
  152.  
  153.             return;
  154.         }
  155.  
  156.         // Grouping selectors by domains
  157.  
  158.         let domains = {__proto__: null};
  159.         for each (var filter in this.filters)
  160.         {
  161.             let domain = filter.selectorDomain || "";
  162.  
  163.             let list;
  164.             if (domain in domains)
  165.                 list = domains[domain];
  166.             else
  167.             {
  168.                 list = {__proto__: null};
  169.                 domains[domain] = list;
  170.             }
  171.             list[filter.selector] = filter.key;
  172.         }
  173.  
  174.  
  175.         // Joining domains list
  176.  
  177.         let cssData = "";
  178.         let cssTemplate = "-moz-binding: url(" + this.scheme + "://%ID%/#dummy) !important;";
  179.  
  180.         for (let domain in domains)
  181.         {
  182.             let rules = [];
  183.             let list = domains[domain];
  184.             for (let selector in list)
  185.                 rules.push(selector + "{" + cssTemplate.replace("%ID%", list[selector]) + "}\n");
  186.  
  187.             if (domain)
  188.                 cssData += '@-moz-document domain("' + domain.split(",").join('"),domain("') + '"){\n' + rules.join('') + '}\n';
  189.             else {
  190.                 // Only allow unqualified rules on a few protocols to prevent them from blocking chrome
  191.                 cssData += '@-moz-document url-prefix("http://"),url-prefix("https://"),'
  192.                                     + 'url-prefix("mailbox://"),url-prefix("imap://"),'
  193.                                     + 'url-prefix("news://"),url-prefix("snews://"){\n'
  194.                                         + rules.join('')
  195.                                     + '}\n';
  196.             }
  197.         }
  198.  
  199.  
  200.         // Creating new stylesheet
  201.         if (cssData)
  202.         {
  203.  
  204.             try {
  205.                 this.url = ioService.newURI("data:text/css;charset=utf8,/*** Adblock Plus ***/" + encodeURIComponent("\n" + cssData), null, null);
  206.                 styleService.loadAndRegisterSheet(this.url, styleService.USER_SHEET);
  207.             } catch(e) {};
  208.  
  209.         }
  210.  
  211.     },
  212.  
  213.     /**
  214.      * Unapplies current stylesheet URL
  215.      */
  216.     unapply: function()
  217.     {
  218.         if (this.url) {
  219.             try {
  220.                 styleService.unregisterSheet(this.url, styleService.USER_SHEET);
  221.             } catch (e) {}
  222.             this.url = null;
  223.         }
  224.     },
  225.  
  226.     //
  227.     // Factory implementation
  228.     //
  229.  
  230.     createInstance: function(outer, iid)
  231.     {
  232.         if (outer != null)
  233.             throw Cr.NS_ERROR_NO_AGGREGATION;
  234.  
  235.         return this.QueryInterface(iid);
  236.     },
  237.  
  238.     //
  239.     // Protocol handler implementation
  240.     //
  241.     defaultPort: -1,
  242.     protocolFlags: Ci.nsIProtocolHandler.URI_STD |
  243.                                  Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD |
  244.                                  Ci.nsIProtocolHandler.URI_NON_PERSISTABLE,
  245.     scheme: "abp-elemhidehit-" + Math.random().toFixed(15).substr(5),
  246.     allowPort: function() {return false},
  247.  
  248.     newURI: function(spec, originCharset, baseURI)
  249.     {
  250.         var url = Cc["@mozilla.org/network/standard-url;1"].createInstance(Ci.nsIStandardURL);
  251.         url.init(Ci.nsIStandardURL.URLTYPE_STANDARD,
  252.                             0, spec, originCharset, baseURI);
  253.         return url;
  254.     },
  255.  
  256.     newChannel: function(uri)
  257.     {
  258.         if (!/:\/+(\d+)\//.test(uri.spec))
  259.             throw Cr.NS_ERROR_FAILURE;
  260.  
  261.         return new HitRegistrationChannel(uri, RegExp.$1);
  262.     },
  263.  
  264.     QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory, Ci.nsIProtocolHandler])
  265. };
  266. abp.elemhide = elemhide;
  267.  
  268. function HitRegistrationChannel(uri, key)
  269. {
  270.     this.key = key;
  271.     this.URI = this.originalURI = uri;
  272. }
  273. HitRegistrationChannel.prototype = {
  274.     key: null,
  275.     URI: null,
  276.     originalURI: null,
  277.     contentCharset: "utf-8",
  278.     contentLength: 0,
  279.     contentType: "text/xml",
  280.     owner: null,
  281.     securityInfo: null,
  282.     notificationCallbacks: null,
  283.     loadFlags: 0,
  284.     loadGroup: null,
  285.     name: null,
  286.     status: Cr.NS_OK,
  287.  
  288.     asyncOpen: function(listener, context)
  289.     {
  290.         let data = "<bindings xmlns='http://www.mozilla.org/xbl'><binding id='dummy'/></bindings>";
  291.         let filter = elemhide.keys[this.key];
  292.         if (filter)
  293.         {
  294.             let wnd = getRequestWindow(this);
  295.             if (wnd && wnd.document && !policy.processNode(wnd, wnd.document, policy.type.ELEMHIDE, filter))
  296.                 data = "<nada/>";
  297.         }
  298.  
  299.         let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
  300.         stream.setData(data, data.length);
  301.  
  302.         runAsync(function()
  303.         {
  304.             try {
  305.                 listener.onStartRequest(this, context);
  306.             } catch(e) {}
  307.             try {
  308.                 listener.onDataAvailable(this, context, stream, 0, data.length);
  309.             } catch(e) {}
  310.             try {
  311.                 listener.onStopRequest(this, context, Cr.NS_OK);
  312.             } catch(e) {}
  313.         }, this);
  314.     },
  315.  
  316.     open: function()
  317.     {
  318.         throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  319.     },
  320.     isPending: function()
  321.     {
  322.         return false;
  323.     },
  324.     cancel: function()
  325.     {
  326.         throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  327.     },
  328.     suspend: function()
  329.     {
  330.         throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  331.     },
  332.     resume: function()
  333.     {
  334.         throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  335.     },
  336.  
  337.     QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
  338. };
  339.